package com.tn.dao;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.Query;
import com.tn.bo.ApplicationNews;
import com.tn.bo.Company;
import com.tn.bo.CreditMemo;
import com.tn.bo.Invoice;
import com.tn.bo.LastUserLogin;
import com.tn.bo.POHeader;
import com.tn.bo.Payment;
import com.tn.service.OfyDataService;

public class NotificationsDAO {
	/** */
	public static final String SUPPLIER_PAYMENTS = "SUPPLIER_PAYMENTS";

	/** */
	public static final String SUPPLIER_PO = "SUPPLIER_PO";

	/** */
	public static final String BUYER_MEMOS = "BUYER_MEMOS";

	/** */
	public static final String BUYER_INVOICES = "BUYER_INVOICES";

	/** */
	public Map<String, String> msgFormatsMap = new HashMap<String, String>();

	public NotificationsDAO() {
		msgFormatsMap.put(BUYER_INVOICES, "{0} invoices received.");
		msgFormatsMap.put(BUYER_MEMOS, "{0} credit memos received");
		msgFormatsMap.put(SUPPLIER_PO, "{0} purchase orders received.");
		msgFormatsMap.put(SUPPLIER_PAYMENTS, "{0} payments received.");
	}

	public LastUserLogin insertLastLogin(String companyId, Long userId) {
		LastUserLogin login = new LastUserLogin();
		login.setCompanyId(companyId);
		login.setUserProfileId(userId);
		login.setLastLoginTime(new Date());
		Objectify txn = OfyDataService.getInstance().beginOfyTransaction();
		txn.put(login);
		OfyDataService.getInstance().commitOfyTransaction(txn);
		return login;
	}

	public LastUserLogin getLastLogin(String companyId) {
		Objectify ofy = OfyDataService.getInstance().getOfyService();
		Query<LastUserLogin> poQuery = ofy.query(LastUserLogin.class).filter(
				"companyId", companyId);
		poQuery.order("-lastLoginTime");
		poQuery.limit(1);
		return poQuery.get();
	}

	/**
	 * Method to get all the notifications for a given companyId.
	 * 
	 * @param company
	 *            company for which we need notifications.
	 * @param lastLogin
	 *            last login time when any user logged in the system.
	 * @param isBuyer
	 *            true if logged in as buyer.
	 * @return Map of notifications.
	 */
	public Map<String, String> getNotificatinsForUser(Company company,
			Date lastLogin, boolean isBuyer) {
		Map<String, String> retVal = new HashMap<String, String>();
		// find all the purchase orders received.
		Objectify ofy = OfyDataService.getInstance().getOfyService();
		Query<POHeader> poQuery = ofy.query(POHeader.class);
		poQuery.filter("orderSupplier", company.getCompanyId());
		poQuery.filter("orderSubmittedDate <=", lastLogin);
		poQuery.order("-orderSubmittedDate");

		int count = 0;
		List<String> keySet = new ArrayList<String>();
		for (POHeader header : poQuery) {
			if (!keySet.contains(header.getOrderNumber())) {
				System.out
						.println("Order Number => " + header.getOrderNumber());
				keySet.add(header.getOrderNumber());
				count++;
			}
		}

		String msg = null;
		// if (count != 0) {
		if (!isBuyer) {
			msg = MessageFormat.format(this.msgFormatsMap.get(SUPPLIER_PO),
					poQuery.count());
			retVal.put(SUPPLIER_PO, msg);
		}
		// }

		Query<Invoice> invoicesQuery;
		// get Invoices received
		invoicesQuery = ofy.query(Invoice.class);
		invoicesQuery.filter("invoicedToCompany", company
				.getCompanyUniqueIdentifier());
		invoicesQuery.filter("invoiceSubmittedDate >=", lastLogin);
		invoicesQuery.order("-invoiceSubmittedDate");

		keySet.clear();
		count = 0;
		for (Invoice invoice : invoicesQuery) {
			if (keySet.contains(invoice.getInvoiceNumber())) {
				continue;
			}
			count++;
			keySet.add(invoice.getInvoiceNumber());
		}

		// if (count != 0) {
		if (isBuyer) {
			msg = MessageFormat.format(this.msgFormatsMap.get(BUYER_INVOICES),
					invoicesQuery.count());
			retVal.put(BUYER_INVOICES, msg);
		}

		// get payments received
		Query<Payment> paymentQuery = ofy.query(Payment.class);
		paymentQuery.filter("paymentRecipientMainCompany", company
				.getCompanyId());
		paymentQuery.filter("paymentSubmittedDate >=", lastLogin);
		paymentQuery.order("-paymentSubmittedDate");

		count = 0;
		keySet.clear();

		for (Payment payment : paymentQuery) {
			if (keySet.contains(payment.getPaymentNumber())) {
				continue;
			}
			count++;
			keySet.add(payment.getPaymentNumber());
		}

		// if (count != 0) {
		if (!isBuyer) {
			msg = MessageFormat.format(this.msgFormatsMap
					.get(SUPPLIER_PAYMENTS), paymentQuery.count());
			retVal.put(SUPPLIER_PAYMENTS, msg);
		}

		Query<CreditMemo> memosQuery;

		// get cash memos received
		memosQuery = ofy.query(CreditMemo.class);
		memosQuery.filter("creditMemoToCompany", company
				.getCompanyUniqueIdentifier());
		memosQuery.filter("creditMemoSubmittedDate >= ", lastLogin);
		memosQuery.order("-creditMemoSubmittedDate");

		count = 0;
		keySet.clear();

		for (CreditMemo memo : memosQuery) {
			if (keySet.contains(memo.getCreditMemoNumber())) {
				continue;
			}
			count++;
			keySet.add(memo.getCreditMemoNumber());
		}

		// if (count != 0) {
		if (isBuyer) {
			msg = MessageFormat.format(this.msgFormatsMap.get(BUYER_MEMOS),
					count);
			retVal.put(BUYER_MEMOS, msg);
		}

		return retVal;
	}

	/**
	 * Method to insert the news into database.
	 * 
	 * @param msg
	 *            Message to insert
	 * @param startDate
	 *            Start date from when we need to start displaying the news.
	 * @param endDate
	 *            Till which date news should be displayed.
	 * @return Recently inserted news.
	 */
	public ApplicationNews insertApplicationNews(String msg, Date startDate,
			Date endDate) {
		ApplicationNews news = new ApplicationNews();
		news.setNewsMsg(msg);
		news.setEffectiveStartDate(startDate);
		news.setEffectiveEndDate(endDate);
		Objectify txn = OfyDataService.getInstance().beginOfyTransaction();
		txn.put(news);
		OfyDataService.getInstance().commitOfyTransaction(txn);
		return news;
	}

	/**
	 * Method to get recent news on application level. The news are sorted in
	 * desc order based on effective date, so that latest news appear on top.
	 * 
	 * @return list of current news.
	 */
	public List<String> getCurrentNews() {
		List<String> retVal = new ArrayList<String>();
		Date currentDate = new Date();

		Objectify ofy = OfyDataService.getInstance().getOfyService();
		Query<ApplicationNews> newsQuery = ofy.query(ApplicationNews.class);
		newsQuery.filter("effectiveStartDate <=", currentDate);
		newsQuery.order("-effectiveStartDate");

		for (ApplicationNews news : newsQuery) {
			if (news.getEffectiveEndDate().after(currentDate)) {
				retVal.add(news.getNewsMsg());
			}
		}
		return retVal;
	}
}
